/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package slicer_20;

//import java.awt.Color;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.*;

import java.util.ArrayList;

import javax.swing.JPanel;

/**
 * MyPanel extendar Jpanel och lägger till all den funtionalitet jag behöver
 * @author Mikael Köhlmyr | mikael@kohlmyr.com | http://www.kmyr.net
 */
public class MyPanel extends JPanel implements MouseListener, MouseMotionListener, KeyListener{
    public Point inUse;
    public int active = -1;
    /**
     * Jag kunde istället för att använda två separata listor gjort en tvådimensionell arraylist,
     * men i och med att jag kommit så långt och genomgående använt två olika utan att tänka på
     * det så valde jag att behålla dem separata då det är krångligt att ändra på det nu samt att
     * jag inte tjänar speciellt mycket på det då vi väldigt sällan behöver ändra någonting i Colors.
     */
    public ArrayList<MyRectangle> Rectangles = new ArrayList<MyRectangle>();
    public ArrayList<Color> Colors = new ArrayList<Color>();
    public MyColorChooser MyCC;
    public Exporter Xport;
    public MyRectangle rectCopy;
    public int hh;
    public int ww;
    public Color colorCopy;
    public long framecap;
    public long lastframe;
    public boolean ctrl = false;
    
    public MyPanel() {
        addMouseMotionListener(this);
        addMouseListener(this);
        this.setFocusable(true);
        addKeyListener(this);
        framecap = 16; // 1 / FPS (60) * 1000 (Millis) = 16
        lastframe = System.currentTimeMillis();

    }
    /**
     * newSquare kollar om användaren klickat någonstans och skapar i sådana fall en rektangel på den positionen.
     *
    **/
    public void newSquare(){
        if(inUse != null){
            MyRectangle nrect = new MyRectangle(inUse, new Point(inUse.x +55, inUse.y +55));
            Rectangles.add(nrect);
            Colors.add(Color.GRAY);
            repaint();
        }
        
    }

    /**
     * newSquare med parametern dimensions används om användaren istället för kotrkommandon använt sig av menyerna. 
     * Den skapar en ny rektangel med de dimensioner användaren specifierat på den position av skärmen där användaren
     * senast klickade.
     * @param dimensions
     */
    public void newSquare(String dimensions){
        String[] str = dimensions.split(" ");
        int w = Integer.parseInt(str[0]);
        int h = Integer.parseInt(str[1]);
        if(inUse != null){
            MyRectangle nrect = new MyRectangle(inUse, new Point(inUse.x + w, inUse.y + h));
            Rectangles.add(nrect);
            Colors.add(Color.GRAY);
            repaint();
        }
    }

    /**
     * moveSquare tar emot en parameter av typen Point. Denna beskriver en förflyttning i 2D-rymden. moveSquare adderar förflyttningen med den aktiva rektangelens position.
     * @param translate
     */
    public void moveSquare(Point translate){
        Rectangles.get(active).x += translate.x;
        Rectangles.get(active).y += translate.y;
        repaint();
    }

    /**
     * reshapeSquare tar också emot en parameter av typen Point. Denna gång ökar eller minskar man rektangelens bredd och höjd med Punktens värden.
     * @param transform
     */
    public void reshapeSquare(Point transform){
        Rectangles.get(active).width += transform.x;
        Rectangles.get(active).height += transform.y;
        repaint();
    }

    /**
     * delta tar emot två punkter och räknar ut skillnaden i rymd mellan dessa, detta används för förflyttningar och liknande.
     * @param from
     * @param to
     * @return
     */
    public Point delta(Point from, Point to){
        Point delta = new Point();
        delta.y = to.y - from.y;
        delta.x = to.x - from.x;
        return delta;
    }
    /**
     * getActiveSquare returnerar den rektangel vi för tillfället arbetar med. Vilken som är aktiv beror på vilken man senaste klickade inom.
     * @return
     */
    public int getActiveSquare(){
        if(!Rectangles.isEmpty()){
            for(int i = 0; i < Rectangles.size(); i++){
                if(Rectangles.get(i).contains(inUse)){
                    return i;
                }
            }
        }
        return -1;
    }
    /**
     * Kallar på getActiveSquare och sätter dess retur-värde till variabeln active
     */
    public void activateSquare(){
            active = getActiveSquare();
    }

    /**
     * paintComponent används för att rita ut våra fyrkanter. vi kallar repaint() så fort ett objekt blivit ändrat och då körs paintComponent()
     * @param g
     */
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if(!Rectangles.isEmpty()){
            for(int i = 0; i < Rectangles.size(); i++){
                g.setColor(Colors.get(i));
                g.fillRect(Rectangles.get(i).x, Rectangles.get(i).y, Rectangles.get(i).width, Rectangles.get(i).height);
            }
        }
    }




    public void mouseClicked(MouseEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    /**
     * mousePressed lyssnar på nedtryckningar av musen och använder detta för att dels sätta inUse och även köra activateSquare.
     * @param e
     */
    public void mousePressed(MouseEvent e) {
        inUse = e.getPoint();
        activateSquare();
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public void mouseReleased(MouseEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public void mouseEntered(MouseEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public void mouseExited(MouseEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    /**
     * mouseDragged lyssnar efter hurvida musen dragits medans knappen är nedtryckt. 
     * Just denna metoden är otroligt viktig då alla våra kommandon för att forma om eller
     * förflytta rektanglar kommer just härifrån.
     * Standardreaktionen är att flytta på rektanglar, men om ctrl hålls inne och man drar
     * muspekaren i kanten av rektangeln så formar man istället om den.
     * @param e
     */
    public void mouseDragged(MouseEvent e) {
        if(System.currentTimeMillis() > framecap + lastframe){
        if(!ctrl && active != -1 && Rectangles.get(active).contains(inUse)){
            Point translate = delta(inUse, e.getPoint());
            moveSquare(translate);
        }
        else if(ctrl && active != -1 && Rectangles.get(active).contains(inUse)){
            Point diff = delta(inUse, e.getPoint());
            Point diff_i = delta(e.getPoint(), inUse);
            
                if(inUse.y >= Rectangles.get(active).y && inUse.y <= Rectangles.get(active).y + 5){
                    moveSquare(new Point(0,diff.y));
                    reshapeSquare(new Point(0,diff_i.y));
                }
                else if(inUse.y <= Rectangles.get(active).y + Rectangles.get(active).height && inUse.y >= Rectangles.get(active).y + Rectangles.get(active).height -5){
                    reshapeSquare(new Point(0,diff.y));
                }
                else if(inUse.x  >= Rectangles.get(active).x && inUse.x <= Rectangles.get(active).x +5){
                    moveSquare(new Point(diff.x,0));
                    reshapeSquare(new Point(diff_i.x,0));
                }
                else if(inUse.x  <= Rectangles.get(active).x + Rectangles.get(active).width && inUse.x >= Rectangles.get(active).x + Rectangles.get(active).width -5){
                    reshapeSquare(new Point(diff.x,0));
                }
            repaint(); 
        }
        lastframe = System.currentTimeMillis();
        inUse = e.getPoint();
        }
    }

    public void mouseMoved(MouseEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }


    public void keyTyped(KeyEvent e) {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    /**
     * keyPressed lyssnar på tangenter. De tangenter vi bryr oss om är control, piltangenterna, delete, v, e samt n och c.
     * Tangenten C har olika funktion beroende på hurvida control är intryckt, med control agerar den copy, utan tar den upp färgvalsmenyn.
     * @param e
     */
    public void keyPressed(KeyEvent e) {
        if(active != -1){
            if(e.getKeyCode() == KeyEvent.VK_UP){
                if(ctrl){
                    reshapeSquare(new Point(0,1));
                }
                moveSquare(new Point(0,-1));
            }
            if(e.getKeyCode() == KeyEvent.VK_DOWN){
                if(ctrl){
                    reshapeSquare(new Point(0,-1));
                }
                moveSquare(new Point(0,1));
            }
            if(e.getKeyCode() == KeyEvent.VK_LEFT){
                if(ctrl){
                    reshapeSquare(new Point(1,0));
                }
                moveSquare(new Point(-1,0));
            }
            if(e.getKeyCode() == KeyEvent.VK_RIGHT){
                if(ctrl){
                    reshapeSquare(new Point(-1,0));
                }
                moveSquare(new Point(1,0));
            }
            if(e.getKeyCode() == KeyEvent.VK_DELETE){
                Rectangles.remove(active);
                Colors.remove(active);
                repaint();
            }
            if(e.getKeyCode() == KeyEvent.VK_C){
                if(ctrl){
                    ww = Rectangles.get(active).width;
                    hh = Rectangles.get(active).height;

                    colorCopy = Colors.get(active);
                    
                }
                else{
                    MyCC = new MyColorChooser(this);
                }
            }
        }
        if(e.getKeyCode() == KeyEvent.VK_V && ctrl && inUse != null){
                    rectCopy = new MyRectangle(new Point(inUse.x, inUse.y), new Point(inUse.x + ww, inUse.y + hh));
                    Rectangles.add(rectCopy);
                    Colors.add(colorCopy);
                    repaint();
            }
        if(e.getKeyCode() == KeyEvent.VK_N && ctrl && inUse != null){
            newSquare();
            }
        if(e.getKeyCode() == KeyEvent.VK_E && ctrl){
            Xport = new Exporter(this);
        }
        if(e.getKeyCode() == KeyEvent.VK_CONTROL){
                ctrl = true;
            }

    }

    /**
     * notifyChoice kallas från färgvalsmenyn, om den kallas så byter vi färg på en av rektanglarna samt ritar om.
     */
    public void notifyChoice(){
        //System.out.println(MyCC.choice);
        Colors.set(active, MyCC.choice);
        repaint();
    }

    /**
     * keyReleased lyssnar enbart efter control då detta är vår "modifier" alltså att olika tangenter gör olika saker beroende på om denna är nedtryckt eller ej.
     * @param e
     */
    public void keyReleased(KeyEvent e) {
        if(e.getKeyCode() == KeyEvent.VK_CONTROL){
                ctrl = false;
                //System.out.println("released ctrl");
        }
        //throw new UnsupportedOperationException("Not supported yet.");
    }

}
